package com.tangyuan.niochat.protocol;

import java.util.HashMap;
import java.util.Map;

import com.tangyuan.niochat.protocol.comman.Command;
import com.tangyuan.niochat.protocol.comman.SerializerAlgorithm;
import com.tangyuan.niochat.protocol.request.LoginRequestPacket;
import com.tangyuan.niochat.protocol.serializer.JSONSerializer;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;

/**
 * Created on 2019-08-28
 * 数据传输包的编码解码
 * @author fenghongyu
 */
public class PacketCode {

    public static final PacketCode INSTANCE = new PacketCode();

    private static final int MAGIC_NUMBER = 0x12345678;
    private Map<Byte, Class<? extends Packet>> packetTypeMap;
    private Map<Byte, Serializer> serializerAlgorithmMap;

    private PacketCode() {
        packetTypeMap = new HashMap<>();
        packetTypeMap.put(Command.LOGIN_REQUEST, LoginRequestPacket.class);

        serializerAlgorithmMap = new HashMap<>();
        serializerAlgorithmMap.put(SerializerAlgorithm.JSON, new JSONSerializer());
    }

    /**
     * java对象编码成二进制
     * 字节顺序为：魔数-4字节|版本号-1字节|序列化算法：1字节|指令：1字节|：数据长度：4字节|数据：N字节
     * @param packet
     * @return
     */
    public ByteBuf encode(ByteBufAllocator allocator, Packet packet) {
        //1.创建ByteBuf对象
        ByteBuf buf = allocator.ioBuffer();
        //2.序列化Java对象
        Serializer serializer = new JSONSerializer();
        byte[] obBytes = serializer.serializer(packet);
        buf.writeInt(MAGIC_NUMBER);
        buf.writeByte(packet.getVersion());
        buf.writeByte(serializer.getSerializerAlgorithm());
        buf.writeByte(packet.getCommand());
        buf.writeInt(obBytes.length);
        buf.writeBytes(obBytes);
        return buf;
    }

    /**
     * 二进制 转码成对应的Java对象
     * 字节顺序为：魔数-4字节|版本号-1字节|序列化算法：1字节|指令：1字节|：数据长度：4字节|数据：N字节
     * @param byteBuf
     * @return
     */
    public Packet decode(ByteBuf byteBuf) {
        //跳过魔数
        byteBuf.skipBytes(4);
        //目前用不到版本号，先跳过
        byteBuf.skipBytes(1);
        //获取序列化算法
        byte serializaAlgorith = byteBuf.readByte();
        //获取数据包的指令
        byte command = byteBuf.readByte();
        //获取数据包的长度
        int length = byteBuf.readInt();
        byte[] bytes = new byte[length];
        //将传输的数据解析出来 TODO 关于粘包 拆包等，后续再优化。
        byteBuf.readBytes(bytes);
        Serializer serializer = getSerializerAlgorithm(serializaAlgorith);
        Class<? extends Packet> packetTypeClazz = getPacketType(command);
        if(serializer != null && packetTypeClazz != null) {
            return serializer.deserializer(packetTypeClazz, bytes);
        }
        return null;
    }

    private Serializer getSerializerAlgorithm(byte serializaAlgorith) {
        return serializerAlgorithmMap.get(serializaAlgorith);
    }

    public Class<? extends Packet> getPacketType(byte b) {
        return  packetTypeMap.get(b);
    }
}
